package com.wawayaya.bookreader.stroke;

import android.util.Log;

/** class to parse .wav file, header part, code from windows C++
 * 
 * @author WanKang
 */
public class WaveParser {
	/// for log only
	private static final String TAG = WaveParser.class.getSimpleName();
	/// wave format, 1 for PCM
	protected int mFormat = 0;
	/// wave sample rate, typical 16000, 22050
	protected int mSampleRate = 0;
	/// actual wave data size
	protected int mDataSize = 0;
	/// channel of wave
	protected int mChannel = 0;
	/// BYTEs size of header part
	protected int mHeadSize = 0;
	
	public int getFormat() {
		return mFormat;
	}
	
	public int getSampleRate() {
		return mSampleRate;
	}
	
	public int getDataSize() {
		return mDataSize;
	}
	
	public int getChannel() {
		return mChannel;
	}
	
	public int getHeaderSize() {
		return mHeadSize;
	}
	
	public boolean parseWave(byte[] bData) {
		int nSize;
		if (bData == null || (nSize=bData.length) <= 16)
			return false;
		String str = new String(bData, 0, 4);
		str = str.toUpperCase();
		if (str.compareTo("RIFF") != 0)
			return false;
		int nFileSize = getInt(bData, 4);
		if (nFileSize != nSize - 8) {
			Log.d(TAG, "size dismatch");
			return false;
		}
		str = new String(bData, 8, 4);
		str = str.toUpperCase();
		if (str.compareTo("WAVE") != 0)
			return false;
		str = new String(bData, 12, 4);
		str = str.toLowerCase();
		if (str.compareTo("fmt ") != 0)
			return false;
		int nFmtSize = getInt(bData, 16);
		if (nFmtSize < 16 || nFmtSize+28 >= nSize)
			return false;
		// to save wave parameter
		mFormat = getShort(bData, 20);
		mChannel = getShort(bData, 22);
		mSampleRate = getInt(bData, 24);
		// to read other segment
		int nNextIdx = nFmtSize + 20;
		str = new String(bData, nNextIdx, 4);
		str = str.toLowerCase();
		// "fact" or some other segments
		while(str.compareTo("data") != 0) {
			int nDataSize = getInt(bData, nNextIdx+4);
			if (nDataSize <= 0 || nDataSize + nNextIdx + 8 > nSize)
				return false;
			nNextIdx += nDataSize + 8;
			if (nNextIdx + 8 > nSize)
				return false;
			str = new String(bData, nNextIdx, 4);
			str = str.toLowerCase();
		}
		// "data" segment, skip it
		int nDataSize = getInt(bData, nNextIdx+4);
		if (nDataSize <= 0 || nDataSize + nNextIdx + 8 > nSize)
			return false;
		mDataSize = nDataSize;
		mHeadSize = nNextIdx + 8;
		return true;
	}
	
	public static int getSkipBytes(byte[] bData) {
		WaveParser wp = new WaveParser();
		if (!wp.parseWave(bData))
			return 0;
		return wp.mHeadSize;
	}
	
	static public int getInt(byte[] bData, int nIndex) {
		if (bData==null || nIndex<0 || nIndex+4>bData.length) {
			Log.d(TAG, "invalid index");
			return 0;
		}
		int b0 = (int)(bData[nIndex+0] & 0xff);
		int b1 = (int)(bData[nIndex+1] & 0xff);
		int b2 = (int)(bData[nIndex+2] & 0xff);
		int b3 = (int)(bData[nIndex+3] & 0xff);
		return b0 + (b1 << 8) + (b2 << 16) + (b3 << 24);
	}

	static public int getShort(byte[] bData, int nIndex) {
		if (bData==null || nIndex<0 || nIndex+2>bData.length) {
			Log.d(TAG, "invalid index");
			return 0;
		}
		int b0 = (int)(bData[nIndex+0] & 0xff);
		int b1 = (int)(bData[nIndex+1] & 0xff);
		return b0 + (b1 << 8);
	}
};